import * as Cesium from "cesium";
import * as turf from "@turf/turf";

class MeasureTools {
    constructor(viewer) {
        this.viewer = viewer;
        this.handler = null;
        this.positions = [];
        this.tempPositions = [];
        this.drawingEntity = null;
        this.labelEntity = null;
        this.measureType = null;
        this.tempPoints = [];
        this.measureEntities = [];
        this.init();
    }

    init() {
        this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
    }

    // 清除测量
    clear() {
        if (this.handler) {
            this.handler.destroy();
            this.handler = null;
        }

        // 清除所有测量实体
        this.measureEntities.forEach(entity => {
            this.viewer.entities.remove(entity);
        });
        this.measureEntities = [];

        // 清除当前正在测量的临时实体
        if (this.drawingEntity) {
            this.viewer.entities.remove(this.drawingEntity);
            this.drawingEntity = null;
        }
        if (this.labelEntity) {
            this.viewer.entities.remove(this.labelEntity);
            this.labelEntity = null;
        }

        // 清除当前的临时点
        this.tempPoints.forEach(point => {
            this.viewer.entities.remove(point);
        });

        this.tempPoints = [];
        this.positions = [];
        this.tempPositions = [];
        this.measureType = null;

        // 重新初始化事件处理器
        this.init();
    }

    // 开始测量
    start(type) {
        // 如果类型相同，不需要重新初始化
        if (this.measureType === type && this.handler) {
            return;
        }

        if (this.measureType !== null && this.handler) {
            // 先清除所有临时点
            this.tempPoints.forEach(point => {
                this.viewer.entities.remove(point);
            });
            this.tempPoints = [];

            // 清除标签实体
            if (this.labelEntity) {
                this.viewer.entities.remove(this.labelEntity);
                this.labelEntity = null;
            }

            // 清除当前正在测量的临时实体
            if (this.drawingEntity) {
                console.log('清除当前正在测量的临时实体');
                this.viewer.entities.remove(this.drawingEntity);
                this.drawingEntity = null;
            }

            // 重置相关数据
            this.positions = [];
            this.tempPositions = [];
            this.measureType = type;
            return;
        }

        // 清除之前的测量
        this.clear();
        this.measureType = type;

        // 注册鼠标事件
        this.handler.setInputAction((movement) => {
            // 拾取地球表面的点
            const cartesian = this.getCartesian3FromPick(movement.position);
            if (!cartesian) return;

            // 添加点实体
            this.addPoint(cartesian);
            this.positions.push(cartesian);

            // 创建或更新临时实体
            if (this.positions.length === 1) {
                this.createTempEntity();
            }

            // 对于角度测量，在选择第三个点后自动完成
            if (this.measureType === 'angle' && this.positions.length === 3) {
                this.tempPositions = [...this.positions];
                this.updateTempEntity();
                this.finish();
                return;
            }

            this.tempPositions = [...this.positions];
            this.updateTempEntity();

        }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

        // 鼠标移动事件
        this.handler.setInputAction((movement) => {
            if (this.positions.length < 1) return;
            const cartesian = this.getCartesian3FromPick(movement.endPosition);
            if (!cartesian) return;

            // 只显示移动轨迹，不计入测量结果
            this.tempPositions = [...this.positions, cartesian];
            this.updateTempEntity(true); // 传入 true 表示是临时显示

        }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

        // 右键结束测量
        this.handler.setInputAction(() => {
            // 使用最后一个点击的位置作为最终结果
            this.tempPositions = [...this.positions];
            this.updateTempEntity();
            this.finish();
        }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
    }

    // 获取地表坐标
    getCartesian3FromPick(windowPosition) {
        const ray = this.viewer.camera.getPickRay(windowPosition);
        return this.viewer.scene.globe.pick(ray, this.viewer.scene);
    }

    // 添加点实体
    addPoint(position) {
        if (this.measureType === 'height' && this.tempPoints.length == 2) {
            // 高程测量只需要两个点，需要删除之前最后一个点，并重新加点
            this.viewer.entities.remove(this.tempPoints.pop());
        }
        const point = this.viewer.entities.add({
            position: position,
            point: {
                pixelSize: 15,
                color: this.measureType === 'height' && this.positions.length === 0 ?
                    Cesium.Color.BLUE :
                    Cesium.Color.RED.withAlpha(0.9),
                outlineColor: Cesium.Color.WHITE,
                outlineWidth: 2,
                heightReference: this.measureType === 'height' ?
                    Cesium.HeightReference.NONE :
                    Cesium.HeightReference.CLAMP_TO_GROUND,
                disableDepthTestDistance: Number.POSITIVE_INFINITY
            }
        });

        // 只为非高程测量起点添加序号标签
        if (this.measureType != 'height') {
            point.label = {
                text: (this.positions.length + 1).toString(),
                font: 'bold 12px sans-serif',
                style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                fillColor: Cesium.Color.WHITE,
                outlineColor: Cesium.Color.BLACK,
                outlineWidth: 2,
                verticalOrigin: Cesium.VerticalOrigin.CENTER,
                horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
                heightReference: this.measureType === 'height' ?
                    Cesium.HeightReference.NONE :
                    Cesium.HeightReference.CLAMP_TO_GROUND,
                disableDepthTestDistance: Number.POSITIVE_INFINITY,
                pixelOffset: new Cesium.Cartesian2(0, 0),
                scaleByDistance: new Cesium.NearFarScalar(1.0e2, 1.0, 1.0e7, 1.0)
            };
        }

        this.tempPoints.push(point);
    }

    // 创建临时实体
    createTempEntity() {
        if (this.measureType === 'angle') {
            this.drawingEntity = this.viewer.entities.add({
                polyline: {
                    positions: new Cesium.CallbackProperty(() => {
                        if (this.tempPositions.length < 2) return [];
                        if (this.tempPositions.length === 2) {
                            return [this.tempPositions[0], this.tempPositions[1]];
                        }
                        return [
                            this.tempPositions[0],
                            this.tempPositions[1],
                            this.tempPositions[2]
                        ];
                    }, false),
                    width: 4,
                    material: Cesium.Color.YELLOW,
                    clampToGround: true
                }
            });
        } else if (this.measureType === 'distance') {
            this.drawingEntity = this.viewer.entities.add({
                polyline: {
                    positions: new Cesium.CallbackProperty(() => {
                        return this.tempPositions;
                    }, false),
                    width: 4,
                    material: new Cesium.PolylineDashMaterialProperty({
                        color: Cesium.Color.YELLOW
                    }),
                    clampToGround: true
                }
            });
        } else if (this.measureType === 'height') {
            // 高程测量使用三条线段：底部水平线、垂直线和顶部水平线
            this.drawingEntity = this.viewer.entities.add({
                polyline: {
                    positions: new Cesium.CallbackProperty(() => {
                        if (this.tempPositions.length < 2) return [];

                        const startPosition = this.tempPositions[0];
                        const endPosition = this.tempPositions[this.tempPositions.length - 1];

                        // 获取经纬度和高度
                        const start = Cesium.Cartographic.fromCartesian(startPosition);
                        const end = Cesium.Cartographic.fromCartesian(endPosition);

                        // 判断哪个点更低
                        if (start.height <= end.height) {
                            // 起点更低，垂直线从起点位置向上
                            const bottomStart = Cesium.Cartesian3.fromRadians(
                                start.longitude,
                                start.latitude,
                                start.height
                            );
                            const verticalEnd = Cesium.Cartesian3.fromRadians(
                                start.longitude,
                                start.latitude,
                                end.height
                            );
                            return [bottomStart, verticalEnd, verticalEnd, endPosition];
                        } else {
                            // 终点更低，垂直线从终点位置向上
                            const bottomEnd = Cesium.Cartesian3.fromRadians(
                                end.longitude,
                                end.latitude,
                                end.height
                            );
                            const verticalEnd = Cesium.Cartesian3.fromRadians(
                                end.longitude,
                                end.latitude,
                                start.height
                            );
                            return [startPosition, verticalEnd, verticalEnd, bottomEnd];
                        }
                    }, false),
                    width: 2,
                    material: Cesium.Color.YELLOW
                }
            });
        } else if (this.measureType === 'area') {
            this.drawingEntity = this.viewer.entities.add({
                polygon: {
                    hierarchy: new Cesium.CallbackProperty(() => {
                        return new Cesium.PolygonHierarchy(this.tempPositions);
                    }, false),
                    material: Cesium.Color.YELLOW.withAlpha(0.4),
                    outline: true,
                    outlineColor: Cesium.Color.YELLOW
                }
            });
        }
    }

    // 更新临时实体
    updateTempEntity(isTemp = false) {
        if (!this.drawingEntity) return;

        // 更新测量结果标签
        let measureResult = '';
        if (this.measureType === 'distance') {
            const distance = isTemp ? this.getDistance(this.tempPositions) : this.getDistance(this.positions);
            measureResult = `总距离: ${distance}`;
        } else if (this.measureType === 'area') {
            const area = isTemp ? this.getArea(this.tempPositions) : this.getArea(this.positions);
            measureResult = `面积: ${area}`;
        } else if (this.measureType === 'height') {
            const height = isTemp ? this.getHeight(this.tempPositions) : this.getHeight(this.positions);
            measureResult = `高度差: ${height}`;
        } else if (this.measureType === 'angle') {
            const angle = isTemp ? this.getAngle(this.tempPositions) : this.getAngle(this.positions);
            measureResult = `角度: ${angle}`;
        }

        // 更新或创建标签实体
        let labelPosition;
        if (this.measureType === 'angle' && this.tempPositions.length >= 2) {
            // 角度测量的标签位置在第二个点
            labelPosition = this.tempPositions[1];
        } else if (this.measureType === 'area') {
            // 面积测量的标签位置在多边形的重心
            labelPosition = this.getCenterOfGravityPoint(this.tempPositions);
        } else {
            // 其他测量的标签位置在最后一个点
            labelPosition = this.tempPositions[this.tempPositions.length - 1];
        }

        if (!this.labelEntity) {
            this.labelEntity = this.viewer.entities.add({
                position: labelPosition,
                label: {
                    text: measureResult,
                    font: "bold 16px sans-serif",
                    fillColor: Cesium.Color.RED,
                    outlineColor: Cesium.Color.WHITE,
                    outlineWidth: 2,
                    style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                    pixelOffset: new Cesium.Cartesian2(0, -30),
                    heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
                    disableDepthTestDistance: Number.POSITIVE_INFINITY,
                    backgroundColor: Cesium.Color.BLACK.withAlpha(0.5)
                }
            });
        } else {
            this.labelEntity.position = labelPosition;
            this.labelEntity.label.text = measureResult;
        }


    }


    // 计算距离
    getDistance(positions = this.positions) {

        if (positions.length < 2) return '0 米';

        // 方式一
        // let distance = 0;
        // for (let i = 0; i < positions.length - 1; i++) {
        //     distance += Cesium.Cartesian3.distance(positions[i], positions[i + 1]);
        // }
        // //使用不同单位
        // if (distance < 1000) {
        //     return distance.toFixed(2) + " 米";
        // } else {
        //     return (distance / 1000).toFixed(2) + " 千米";
        // }


        // 方式二
        let totalDistance = 0;
        // 遍历所有点，计算相邻两点之间的距离
        for (let i = 0; i < positions.length - 1; i++) {
            // 将 Cartesian3 坐标转换为经纬度
            const from = Cesium.Cartographic.fromCartesian(positions[i]);
            const to = Cesium.Cartographic.fromCartesian(positions[i + 1]);

            // 创建 turf 点
            const fromPoint = turf.point([
                Cesium.Math.toDegrees(from.longitude),
                Cesium.Math.toDegrees(from.latitude)
            ]);
            const toPoint = turf.point([
                Cesium.Math.toDegrees(to.longitude),
                Cesium.Math.toDegrees(to.latitude)
            ]);

            // 计算距离（单位：千米）
            const segmentDistance = turf.distance(fromPoint, toPoint, { units: 'kilometers' });
            totalDistance += segmentDistance;
        }

        // 格式化输出
        if (totalDistance < 1) {
            return (totalDistance * 1000).toFixed(2) + " 米";
        } else {
            return totalDistance.toFixed(2) + " 千米";
        }
    }

    // 获取多边形
    getPolygon(positions) {
        // 将 Cartesian3 坐标转换为经纬度数组
        let coordinates = positions.map(point => {
            // 将 Cartesian3 转换为经纬度
            const cartographic = Cesium.Cartographic.fromCartesian(point);
            const longitude = Cesium.Math.toDegrees(cartographic.longitude);
            const latitude = Cesium.Math.toDegrees(cartographic.latitude);
            return [longitude, latitude];
        });

        // 确保多边形闭合（首尾点相同）
        if (coordinates[0][0] !== coordinates[coordinates.length - 1][0] ||
            coordinates[0][1] !== coordinates[coordinates.length - 1][1]) {
            coordinates.push(coordinates[0]);
        }
        // 创建 turf.js 多边形
        return turf.polygon([coordinates]);
    }


    //计算多边形面积
    getArea(points) {
        if (points.length < 3) return '0 平方米';

        const polygon = this.getPolygon(points);

        // 计算面积（平方米）
        let res = turf.area(polygon);

        if (res < 1000000) {
            res = Math.abs(res).toFixed(4) + " 平方米";
        } else {
            res = Math.abs((res / 1000000.0).toFixed(4)) + " 平方公里";
        }
        return res;

    };

    /**
     * 计算多边形的重心
     * @param {Array} mPoints - 多边形顶点的笛卡尔坐标数组
     * @returns {Cesium.Cartesian3} 重心点的笛卡尔坐标
     */
    getCenterOfGravityPoint(mPoints) {
        if (!mPoints || mPoints.length < 3) {
            return mPoints[mPoints.length - 1];
        }

        // // 将笛卡尔坐标转换为地理坐标进行计算
        // let sumLon = 0;
        // let sumLat = 0;
        // let sumHeight = 0;
        // let area = 0;
        // let points = mPoints.map(point => Cesium.Cartographic.fromCartesian(point));

        // // 使用多边形面积加权的方式计算重心
        // for (let i = 0; i < points.length; i++) {
        //     let j = (i + 1) % points.length;
        //     let factor = (points[i].longitude * points[j].latitude -
        //         points[j].longitude * points[i].latitude);

        //     area += factor;
        //     sumLon += (points[i].longitude + points[j].longitude) * factor;
        //     sumLat += (points[i].latitude + points[j].latitude) * factor;
        //     sumHeight += (points[i].height + points[j].height) * factor;
        // }

        // area *= 0.5;
        // let factor = 1.0 / (6.0 * area);

        // // 计算重心坐标
        // let centerLon = sumLon * factor;
        // let centerLat = sumLat * factor;
        // let centerHeight = sumHeight * factor;

        // // 转换回笛卡尔坐标
        // return Cesium.Cartesian3.fromRadians(centerLon, centerLat, centerHeight);


        // 方式二：使用turf.js计算重心
        const polygon = this.getPolygon(mPoints);
        // 计算重心
        const center = turf.centerOfMass(polygon);

        // 计算平均高度
        const avgHeight = mPoints.reduce((sum, point) => {
            return sum + Cesium.Cartographic.fromCartesian(point).height;
        }, 0) / mPoints.length;

        // 将重心点转换回笛卡尔坐标
        return Cesium.Cartesian3.fromDegrees(
            center.geometry.coordinates[0],
            center.geometry.coordinates[1],
            avgHeight
        );
    }

    // 计算高程
    getHeight(positions = this.positions) {
        if (positions.length < 2) return 0 + " 米";

        // 获取起点和终点的地理坐标
        const startCartographic = Cesium.Cartographic.fromCartesian(positions[0]);
        const endCartographic = Cesium.Cartographic.fromCartesian(positions[positions.length - 1]);

        // 获取地形高度
        const startHeight = startCartographic.height;
        const endHeight = endCartographic.height;

        // 计算高度差的绝对值
        const heightDifference = Math.abs(endHeight - startHeight);

        // 使用不同单位
        if (heightDifference < 1000) {
            return heightDifference.toFixed(2) + " 米";
        } else {
            return (heightDifference / 1000).toFixed(2) + " 千米";
        }
    }

    // 添加计算角度的方法
    getAngle(positions) {
        if (positions.length < 3) return '0°';

        // 获取三个点的笛卡尔坐标
        const p1 = positions[0];
        const p2 = positions[1];
        const p3 = positions[2];

        // 计算向量
        const vector1 = Cesium.Cartesian3.subtract(p1, p2, new Cesium.Cartesian3());
        const vector2 = Cesium.Cartesian3.subtract(p3, p2, new Cesium.Cartesian3());

        // 归一化向量
        Cesium.Cartesian3.normalize(vector1, vector1);
        Cesium.Cartesian3.normalize(vector2, vector2);

        // 计算点积
        const dotProduct = Cesium.Cartesian3.dot(vector1, vector2);

        // 计算角度（弧度）
        let angle = Math.acos(Cesium.Math.clamp(dotProduct, -1.0, 1.0));

        // 转换为度数
        angle = Cesium.Math.toDegrees(angle);

        return angle.toFixed(1) + '°';
    }

    // 完成测量
    finish() {
        // 如果不是临时显示，将实体添加到测量实体数组中
        // 将当前实体添加到测量实体数组中

        if (this.drawingEntity) {
            // 创建一个永久的测量实体（复制当前的临时实体）
            let permanentEntity;
            if (this.measureType === 'angle') {
                permanentEntity = this.viewer.entities.add({
                    polyline: {
                        positions: this.drawingEntity.polyline.positions.getValue(),
                        width: 4,
                        material: Cesium.Color.YELLOW,
                        clampToGround: true
                    }
                });
            } else if (this.measureType === 'distance') {
                permanentEntity = this.viewer.entities.add({
                    polyline: {
                        positions: this.positions,
                        width: 4,
                        material: new Cesium.PolylineDashMaterialProperty({
                            color: Cesium.Color.YELLOW
                        }),
                        clampToGround: true
                    }
                });
            } else if (this.measureType === 'area') {
                permanentEntity = this.viewer.entities.add({
                    polygon: {
                        hierarchy: new Cesium.PolygonHierarchy(this.positions),
                        material: Cesium.Color.YELLOW.withAlpha(0.4),
                        outline: true,
                        outlineColor: Cesium.Color.YELLOW
                    }
                });
            } else if (this.measureType === 'height') {
                // 复制当前的高程测量实体
                permanentEntity = this.viewer.entities.add({
                    polyline: {
                        positions: this.drawingEntity.polyline.positions.getValue(),
                        width: 2,
                        material: Cesium.Color.YELLOW
                    }
                });
            }

            if (permanentEntity) {
                this.measureEntities.push(permanentEntity);
            }
        }
        if (this.labelEntity) {
            this.measureEntities.push(this.labelEntity);
        }
        if (this.drawingEntity) {
            this.measureEntities.push(this.drawingEntity);
        }
        // 将当前的临时点也添加到测量实体数组中
        this.tempPoints.forEach(point => {
            this.measureEntities.push(point);
        });


        // 保留当前测量结果，只重置变量以准备下一次测量
        this.positions = [];
        this.tempPositions = [];
        this.tempPoints = [];

        // 只将它置为 null 以便下一次测量创建新的实体
        this.labelEntity = null;
    }
}

export default MeasureTools; 